﻿using System;

using System.Collections.Generic;
using System.Text;
using Silvermoon.Shapes;
using System.Drawing;
using Silvermoon.OpenGL.Native;
using Silvermoon.OpenGL;
using Silvermoon.Interfaces;
using Silvermoon.Windows;
using Silvermoon.Controls.Base;
using Silvermoon.UI;

namespace Silvermoon.Controls
{
    /// <summary>
    /// Control to present text in one ore more lines, optionally with word wrap and custom alignments and drop shadow.
    /// </summary>
    public class Label : ChromeControl, IColor
    {
        private StringShape stringShape;
        private bool isShadowed;

        #region ctor/dtor

        public Label()
            : base()
        {
            stringShape = new StringShape
            {
                Alignment = Alignment.Near,
                LineAlignment = Alignment.Center,
                AutoSize = false
            };
            Shapes.AddLast(stringShape);
        }

        public Label(string text)
            : this()
        {
            this.Text = text;
            AutoSize = true;
        }

        public Label(string text, FontSprite font)
            : this(text)
        {
            Font = font;
        }



        #endregion
        #region properties

        public override Size Size
        {
            get
            {
                return AutoSize ? stringShape.Size : base.Size;
            }
            set
            {
                stringShape.Size = Scale(value);
                base.Size = value;
            }
        }


        /// <summary>
        /// Gets or sets the skewness of the character. The bigger the value, the more italic the character appears.
        /// </summary>
        public int Skew
        {
            get { return stringShape.Skew; }
            set
            {
                if (Skew != value)
                {
                    stringShape.Skew = value;
                    Invalidate(InvalidationFlag.Appearance);
                }
            }
        }


        /// <summary>
        /// Gets or sets the number of pixels between each character.
        /// </summary>
        public int CharSpace
        {
            get { return stringShape.CharSpace; }
            set
            {
                if (CharSpace != value)
                {
                    stringShape.CharSpace = value;
                    Invalidate(InvalidationFlag.Appearance);
                }
            }
        }

        /// <summary>
        /// Gets or sets whether the labels size is determined automatically.
        /// </summary>
        public bool AutoSize
        {
            get { return stringShape.AutoSize; }
            set
            {
                if (AutoSize != value)
                {
                    stringShape.AutoSize = value;
                    OnAutoSizeChanged();
                }
            }
        }

        /// <summary>
        /// Gets or sets whether to render with a shadow.
        /// </summary>
        public bool IsShadowed
        {
            get
            {
                return isShadowed;
            }
            set
            {
                if (isShadowed != value)
                {
                    isShadowed = value;
                    stringShape.IsShadowed = IsShadowed;
                    Invalidate(InvalidationFlag.Appearance);
                }
            }
        }

        public Alignment LineAlignment
        {
            get
            {
                return stringShape.LineAlignment;
            }
            set
            {
                stringShape.LineAlignment = value;
            }
        }

        public Alignment Alignment
        {
            get
            {
                return stringShape.Alignment;
            }
            set
            {
                stringShape.Alignment = value;
            }
        }

        public LineMode LineMode
        {
            get
            {
                return stringShape.LineMode;
            }
            set
            {
                stringShape.LineMode = value;
            }
        }

        /// <summary>
        /// Gets or sets the text to display.
        /// </summary>
        public string Text
        {
            get
            {
                return stringShape.Text;
            }
            set
            {
                if (stringShape.Text != value)
                {
                    stringShape.Text = value;
                    OnTextChanged();
                }
            }
        }

        /// <summary>
        /// Gets or sets the font for the text.
        /// </summary>
        public FontSprite Font
        {
            get
            {
                return stringShape.Font;
            }
            set
            {
                if (stringShape.Font != value)
                {
                    stringShape.Font = value;
                    Invalidate(InvalidationFlag.LayoutAppearance);
                }
            }
        }

        /// <summary>
        /// Gets the size that the text actually requires.
        /// </summary>
        public Size TextSize
        {
            get
            {
                return Control.Unscale(stringShape.TextSize);
            }
        }


        /// <summary>
        /// Gets or sets the scale factor for the font.
        /// </summary>
        public float FontScale
        {
            get
            {
                return stringShape.FontScale;
            }
            set
            {
                if (stringShape.FontScale != value)
                {
                    stringShape.FontScale = value;
                    Invalidate(InvalidationFlag.LayoutAppearance);
                }
            }
        }

        #endregion
        #region Methods

        public override Size Measure(Size availableSize)
        {
            if (!Visible) return Size.Empty;
            if (AutoSize)
            {
                int w = availableSize.Width;
                if (w == 0) w = int.MaxValue;
                int h = availableSize.Height;
                if (h == 0) h = int.MaxValue;
                stringShape.Size = new Size(w, h);
                stringShape.PreLoad();
            }
            return base.Measure(availableSize);
        }

        protected override void PreLayout()
        {
            if (AutoSize)
            {
                stringShape.PreLoad();
                Size = stringShape.Size;
            }
            base.PreLayout();
        }

        protected virtual void OnAutoSizeChanged()
        {
            if (AutoSize) Size = stringShape.Size;
        }

        protected virtual void OnTextChanged()
        {
            Invalidate(InvalidationFlag.Text);
        }



        protected override void OnTextColorChanged()
        {
            stringShape.Color = TextColor;
        }

        internal void SetTextColor(Color color)
        {
            stringShape.Color = color;
        }

        #endregion
        #region IColor Members

        Color IColor.Color
        {
            get
            {
                return TextColor;
            }
            set
            {
                TextColor = value;
            }
        }

        #endregion
        #region accessors

        public static readonly PropertyAccessor<Label, float> FontScaleProperty = PropertyAccessor.Register<Label, float>("FontScale", e => ((Label)e).FontScale, (e, v) => ((Label)e).FontScale = v);

        #endregion
        #region operators

        public static implicit operator Label(string text)
        {
            return new Label
            {
                Text = text,
                AutoSize = true
            };
        }

        public static implicit operator Label(int text)
        {
            return new Label
            {
                Text = text.ToString(),
                AutoSize = true
            };
        }

        public static implicit operator Label(float text)
        {
            return new Label
            {
                Text = text.ToString(),
                AutoSize = true
            };
        }

        #endregion
    }
}
